// Utils
import { createNamespace, isDef } from '../utils'
import { isHidden } from '../utils/dom/style'
import { preventDefault } from '../utils/dom/event'
import {
  getScroller,
  getScrollTop,
  getRootScrollTop,
  setRootScrollTop
} from '../utils/dom/scroll' // Mixins

import { TouchMixin } from '../mixins/touch'
import { ParentMixin } from '../mixins/relation'
import { BindEventMixin } from '../mixins/bind-event'

function genAlphabet() {
  var indexList = []
  var charCodeOfA = 'A'.charCodeAt(0)

  for (var i = 0; i < 26; i++) {
    indexList.push(String.fromCharCode(charCodeOfA + i))
  }

  return indexList
}

var _createNamespace = createNamespace('index-bar')
var createComponent = _createNamespace[0]
var bem = _createNamespace[1]

export default createComponent({
  mixins: [
    TouchMixin,
    ParentMixin('emIndexBar'),
    BindEventMixin(function(bind) {
      if (!this.scroller) {
        this.scroller = getScroller(this.$el)
      }

      bind(this.scroller, 'scroll', this.onScroll)
    })
  ],
  props: {
    zIndex: [Number, String],
    highlightColor: String,
    sticky: {
      type: Boolean,
      default: true
    },
    stickyOffsetTop: {
      type: Number,
      default: 0
    },
    indexList: {
      type: Array,
      default: genAlphabet
    }
  },
  data: function data() {
    return {
      activeAnchorIndex: null
    }
  },
  computed: {
    sidebarStyle: function sidebarStyle() {
      if (isDef(this.zIndex)) {
        return {
          zIndex: this.zIndex + 1
        }
      }
    },
    highlightStyle: function highlightStyle() {
      var highlightColor = this.highlightColor

      if (highlightColor) {
        return {
          color: highlightColor
        }
      }
    }
  },
  watch: {
    indexList: function indexList() {
      this.$nextTick(this.onScroll)
    },
    activeAnchorIndex: function activeAnchorIndex(value) {
      if (value) {
        this.$emit('change', value)
      }
    }
  },
  methods: {
    onScroll: function onScroll() {
      var _this = this

      if (isHidden(this.$el)) {
        return
      }

      var scrollTop = getScrollTop(this.scroller)
      var scrollerRect = this.getScrollerRect()
      var rects = this.children.map(function(item) {
        return item.getRect(_this.scroller, scrollerRect)
      })
      var active = this.getActiveAnchorIndex(scrollTop, rects)
      this.activeAnchorIndex = this.indexList[active]

      if (this.sticky) {
        this.children.forEach(function(item, index) {
          if (index === active || index === active - 1) {
            var rect = item.$el.getBoundingClientRect()
            item.left = rect.left
            item.width = rect.width
          } else {
            item.left = null
            item.width = null
          }

          if (index === active) {
            item.active = true
            item.top =
              Math.max(_this.stickyOffsetTop, rects[index].top - scrollTop) +
              scrollerRect.top
          } else if (index === active - 1) {
            var activeItemTop = rects[active].top - scrollTop
            item.active = activeItemTop > 0
            item.top = activeItemTop + scrollerRect.top - rects[index].height
          } else {
            item.active = false
          }
        })
      }
    },
    getScrollerRect: function getScrollerRect() {
      if (this.scroller.getBoundingClientRect) {
        return this.scroller.getBoundingClientRect()
      }

      return {
        top: 0,
        left: 0
      }
    },
    getActiveAnchorIndex: function getActiveAnchorIndex(scrollTop, rects) {
      for (var i = this.children.length - 1; i >= 0; i--) {
        var prevHeight = i > 0 ? rects[i - 1].height : 0
        var reachTop = this.sticky ? prevHeight + this.stickyOffsetTop : 0

        if (scrollTop + reachTop >= rects[i].top) {
          return i
        }
      }

      return -1
    },
    onClick: function onClick(event) {
      this.scrollToElement(event.target)
    },
    onTouchMove: function onTouchMove(event) {
      this.touchMove(event)

      if (this.direction === 'vertical') {
        preventDefault(event)
        var _event$touches$ = event.touches[0]
        var clientX = _event$touches$.clientX
        var clientY = _event$touches$.clientY
        var target = document.elementFromPoint(clientX, clientY)

        if (target) {
          var index = target.dataset.index
          /* istanbul ignore else */

          if (this.touchActiveIndex !== index) {
            this.touchActiveIndex = index
            this.scrollToElement(target)
          }
        }
      }
    },
    scrollTo: function scrollTo(index) {
      var match = this.children.filter(function(item) {
        return String(item.index) === index
      })

      if (match[0]) {
        match[0].scrollIntoView()

        if (this.sticky && this.stickyOffsetTop) {
          setRootScrollTop(getRootScrollTop() - this.stickyOffsetTop)
        }

        this.$emit('select', match[0].index)
      }
    },
    scrollToElement: function scrollToElement(element) {
      var index = element.dataset.index
      this.scrollTo(index)
    },
    onTouchEnd: function onTouchEnd() {
      this.active = null
    }
  },
  render: function render() {
    var _this2 = this

    var h = arguments[0]
    var Indexes = this.indexList.map(function(index) {
      var active = index === _this2.activeAnchorIndex
      return h(
        'span',
        {
          class: bem('index', {
            active: active
          }),
          style: active ? _this2.highlightStyle : null,
          attrs: {
            'data-index': index
          }
        },
        [index]
      )
    })
    return h(
      'div',
      {
        class: bem()
      },
      [
        h(
          'div',
          {
            class: bem('sidebar'),
            style: this.sidebarStyle,
            on: {
              click: this.onClick,
              touchstart: this.touchStart,
              touchmove: this.onTouchMove,
              touchend: this.onTouchEnd,
              touchcancel: this.onTouchEnd
            }
          },
          [Indexes]
        ),
        this.slots('default')
      ]
    )
  }
})
